	
	'
	'  simple app for testing FB.RegExpLib.Compiler
	'
	
	
	#Define FB_REGEXP_LIB_COMPILER_DEBUG ' make all members of FB.RegExpLib.Compiler public
	
	#Include "..\src\fbregexp.bas"
	
	DefineDynamicArrayType( Integer )
	
	Using FB.RegExpLib
	
	Dim As String origregexp, regexp, mulln, icase, again
	
	Dim As Compiler 		compiler
	Dim As Preprocessor	preproc
	
	
	Sub DebugNFAState(s As State Pointer)
		
		Print "State "; Str(s->Index); ":"
		
		If s->accept Then Print "  Accept"
		
		For i As Integer = 0 To s->transition.ItemCount - 1
			If s->transition.Item(i).char = 10 or s->transition.Item(i).char = 13  Then
				Print "  on &h"; Right("00" + Hex(s->transition.Item(i).char), 2); " goto "; Str(s->transition.Item(i).target->Index)
			ElseIf s->transition.Item(i).char = EPSILON Then
				Print "  goto "; Str(s->transition.Item(i).target->Index)
			Else
				Print "  on "; Chr(s->transition.Item(i).char); " goto "; Str(s->transition.Item(i).target->Index)
			EndIf
		Next
		
		Print
		
		For i As Integer = 0 To s->transition.ItemCount - 1
			DebugNFAState s->transition.Item(i).target
		Next
		
	End Sub
	
	
	Sub DOTDigraphState(s As State Pointer, fn As Integer, ByRef processed As IntegerArray)
		
		For i As Integer = 0 To processed.ItemCount - 1
			If s->Index = processed.Item(i) Then Exit Sub
		Next
		
		processed.Add s->Index
		
		If s->accept Then
			Print #fn, "  "; Str(s->Index); " [shape=doublecircle,fixedsize=true];"	
		Else
			Print #fn, "  "; Str(s->Index); " [regular=true,fixedsize=true];"			
		EndIf
		
		Dim As String char
		
		For i As Integer = 0 To s->transition.ItemCount - 1
			
			If s->transition.Item(i).char = 10 Then
				char = "LF"
			ElseIf s->transition.Item(i).char = 13 Then
				char = "CR"
			ElseIf s->transition.Item(i).char = EPSILON Then
				char = ""
			Else
				char = Chr(s->transition.Item(i).char)
			EndIf
			
			If s->transition.Item(i).char = EPSILON Then
				Print #fn, "   "; Str(s->Index); " -> "; Str(s->transition.Item(i).target->Index); " [style=dotted];"
			Else
				Print #fn, "   "; Str(s->Index); " -> "; Str(s->transition.Item(i).target->Index); " [label="""; char; """];"				
			EndIf
			
		Next
		
		For i As Integer = 0 To s->transition.ItemCount - 1
			DOTDigraphState s->transition.Item(i).target, fn, processed
		Next
		
	End Sub
	
	Sub DOTDigraph(s As State Pointer, f As String, re As String)
		
		Dim As Integer fn = FreeFile, result
		Dim As IntegerArray processed
		
		If Len(f) = 0 Then
			result = Open Cons(For Output As #fn)
		Else
			result = Open(f For Output Lock Write As #fn)
		EndIf
		
		If result = 0 Then
			
			Print #fn, "digraph NFA {"
  			Print #fn, " center=true;"
  			Print #fn, " label="""; re; """;"
  			Print #fn, " size=""1000,100"";"
  			
  			DOTDigraphState s, fn, processed
  			
  			Print #fn, "}"
  			
  			Close #fn
			
		EndIf
		
	End Sub
	
	Sub CreatePNGGraph(s As State Pointer, fn As String, re As String)
		
		DOTDigraph s, "~graph.tmpdot", re
		
		Shell "dot -ograph.png -Tpng ~graph.tmpdot"
		
		Kill "~graph.tmpdot"
		
	End Sub
	
	
	Do
		
		Print "----------------------------"
		Print
		Line Input "Enter a regular expression: ", regexp
		Input "Set Multiline flag (y/n)"; mulln
		Input "Set IgnoreCase flag (y/n)"; icase
		Print
		
		origregexp = regexp
		
		If preproc.Preprocess(regexp, LCase(Left(mulln, 1)) = "y", LCase(Left(icase, 1)) = "y") Then
			
			compiler.Pattern = regexp
			compiler.iPos = 0			
			compiler.ErrorDescription = "No error"
			
			Dim As State Pointer	StartState, EndState
			
			compiler.nextState = 0
			
			compiler.NextChar
			
			If compiler.RegExp(StartState, EndState) Then
				
				EndState->accept = True
				
				Dim As Integer choice
				
				Print "What you want to do:"
				Print "  1 - Print debug info"
				Print "  2 - Print DOT digraph"
				Print "  3 - Save DOT digraph to graph.dot"
				Print "  4 - Create graph.png (DOT must be in PATH)"
				
				Do
					
					Print
					Input "Choose (1/2/3/4): ", choice
					
					Select Case As Const choice
						
						Case 1
							
							DebugNFAState StartState
						
						Case 2
							
							DOTDigraph StartState, "", origregexp
						
						Case 3
							
							DOTDigraph StartState, "graph.dot", origregexp
						
						Case 4
							
							CreatePNGGraph StartState, "graph.png", origregexp
						
						Case Else
							
							Continue Do
							
					End Select
					
					Exit Do
					
				Loop
				
			Else
				
				Print "Error: "; compiler.ErrorDescription
				
			EndIf
			
		Else
			
			Print "Error: "; preproc.ErrorDescription
			
		EndIf
		
		Print
		Print
		Input "Continue (y/n)"; again
		
		If LCase(Left(again, 1)) <> "y" Then Exit Do
		
		Print
		Print
		
	Loop
